function gewPhysicsEngine(game,scene3d)
{
  this.game = game;
  this.scene3d = scene3d;
  this.quadTree = scene3d.quadTree;
  this.activeBodys = [];
  this.staticBodys = [];
  this.collisionPairs = {};
  this.ground = null;// a height map act as ground for all physics body
  this.gravity = new gewVec3(0,-9.8,0);
  this.collisionCallBack = function(body1,body2,normal){console.log("Dectected Collise!");}
  scene3d.physicsEngine = this; 
}
gewPhysicsEngine.prototype = {
  // Set callback for a pair collise event, the callback function is in these form : function(body1,body2,normal)
  setCollisionCallBack:function(callbackFunc)
  {
    this.collisionCallBack = callbackFunc;
  },
  onTick:function(mls)
  {
    // find collision
    var pairs = this.collisionPairs;
    for(var i in pairs)
    {
      var pair = pairs[i];
      var normal = new gewVec3();
      var isCollide = pair.testCollision(normal);
      if(isCollide)
      {
        this.collisionCallBack(pair.body1,pair.body2,normal);
      }
    }
    // Apply force
    
    // gravity
    
    var ground = this.ground
    if(this.ground)
    {
      
    }
  },
  addRigidBody:function(sceneNode,isStatic,catalogyBit,maskBits)
  {
    var body = new gewRigidBody(this,sceneNode,isStatic,catalogyBit,maskBits);
    if(isStatic==true)
    {
      body.isStatic = true;
      this.staticBodys.push(body);
    }
    else
    {
      this.activeBodys.push(body);
    }
    return body;
  },
  removeRigidBody:function(body)
  {
    body.removePair();
    if(body.isStatic)
      this.staticBodys.splice(body.idx,1);
    else
      this.activeBodys.splice(body.idx,1);
  }  
}
function gewRigidBody(engine,sceneNode,isStatic,catalogyBit,maskBits)
{
  this.engine = engine;
  this.userData = null;
  this.sceneNode = sceneNode;
  sceneNode.physicsBody = this;
  this.categoryBit = catalogyBit;
  this.maskBits = maskBits;
  this.shape = null;
  // PRIVATE:
  this.velocity = new gewVec3();
  this.collisionPairs = {};
  // static property should not change after body is created
  if(isStatic==true)
    this.isStatic = true; 
  else
    this.isStatic = false;
  this.idx = 0;// idx of this body is engine's list ( for fast remove)
}

gewRigidBody.prototype = {
  setShape:function(shape)
  {
    this.shape = shape;
  },
  setVelocity:function(v)
  {
    this.velocity.set(v.x,v.y,v.z);
  },
  setVelocityXYZ:function(vx,vy,vz)
  {
    this.velocity.set(vx,vy,vz);
  },
  removeFromCell:function(cell)
  {
    var pairs = this.collisionPairs;
    for(var i in pairs)
    {
      var pair = pairs[i];
      if(pair.body1==this)
        var rhsBody = pair.body2;
      else
        var rhsBody = pair.body1;
      if(pair.cells.length==1&& pair.cells[0]==cell)
      {
        pair.destroy();
      }
      else
      {
        removeFromArray(cell,pair.cells);
      }
    } 
  },
  addToCell:function(cell)
  {
    var nodeList = cell.nodeList;
    var nodeNum = nodeList.length;
    var pairs = this.engine.collisionPairs;
    // Find new collision pair
    for(var i=0;i<nodeNum;i++)
    {
      var node = nodeList[i];
      if(node&&node.physicsBody)
      {
        var body = node.physicsBody;
        if(this==body)
          continue;
        if(this.isStatic&&body.isStatic) // two static body
          continue;
        if( (this.maskBits&body.categoryBit)==0 &&
            (this.categoryBit&body.maskBits)==0) // collision filter
          continue;
          
        var name1 = this.sceneNode.name;
        var name2 = node.name;
        if(name1<name2)
          var pairName = name1+name2;
        else
          var pairName = name2+name1;
        
        if(pairs[pairName]) // this pair is already exist!
        {
          pairs[pairName].updateCell();
          continue;
        }
        var new_pair = new gewCollisionPair(this.engine,this,body,pairName);
        pairs[pairName] =   new_pair;
        this.collisionPairs[pairName] = new_pair;  
        body.collisionPairs[pairName] = new_pair;
      }
    }
  }
}

function gewCollisionPair(engine,body1,body2,name)
{
  this.engine = engine;
  this.body1 = body1;
  this.body2 = body2;
  this.cells = [];
  this.name = name;
  this.contactPoints = [];
  this.contactNormals = [];
  this.updateCell();  
}
gewCollisionPair.prototype = {
  testCollision:function(outNormal)
  {
    var b1 = this.body1;
    var b2 = this.body2;
    var node1 = b1.sceneNode;
    var node2 = b2.sceneNode;
    // Do world sphere test
    var sphere1 = node1.worldSphere;
    var sphere2 = node2.worldSphere;
    var test = sphere1.isContainSphere(sphere2);
    if(test==GEW_OUT)
    {
      //console.log("Reject by shpere test");
      return false;
    }
    // Do world aabb test
    var aabb1 = node1.worldAabb;
    var aabb2 = node2.worldAabb;
    test = aabb1.collisionWithAabb(aabb2);
    if(test==GEW_OUT)
    {
      //console.log("Reject by aabb test")
      return false;
    }
       
    var shape1 = b1.shape;
    var shape2 = b2.shape;
    // Do aabb-shape test
    if( (!shape1 && shape2) ||
        (shape1&& !shape2))
    {
      if(!shape1)
      {
        var shape = shape2;
        var localAabb = node1.localAabb;
        var inverseModelMat = node2.modelMat.dup();
        var modelMat = node1.modelMat;
        var shapeModelMat = node2.modelMat;
        var velocity = b1.velocity;
      }
      if(!shape2)
      {
        var shape = shape1;
        var localAabb = node2.localAabb;
        var inverseModelMat = node1.modelMat.dup();
        var modelMat = node2.modelMat;
        var shapeModelMat = node1.modelMat;
        var velocity = b2.velocity;
      }
      if(shape.meshType == GEW_STATIC_MESH) // Shape is a static mesh
      {
        inverseModelMat.inverse();
        var combineMat = inverseModelMat.mul(modelMat);
        // Tranform localAabb from its local coordinate to shape's local coordinate
        var aabb = new gewAabb();
        var localAabbCorners = localAabb.corners;
        var aabbCorners = aabb.corners;
        for(var c=0;c<8;c++)
        {
          combineMat.mulVec3(localAabbCorners[c],aabbCorners[c]);
        }
        aabb.initFromCorner(aabbCorners);
        var outTriangles = [];
        test = aabb.collisionWithMesh( shape.vertices, shape.indices[shape.indices.length-1],outTriangles);
        if(test!=GEW_OUT)
        {
          /*
          var plane = new gewPlane(outTriangle.v0,outTriangle.v1,outTriangle.v2);
          normal.set(plane.a,plane.b,plane.c);
          var v0center = aabb.center.sub(outTriangle.v0);
          var angle = v0center.angleFrom(normal)* GEW_MATH_RADIAN_TO_DEGREE;
          if(angle>90)
            normal.set(-normal.x,-normal.y,-normal.z);
          shapeModelMat.mulVec3NoTranslate(normal,normal);*/
         var maxAngle = 0;
         var minDis = 10000;
         var normal = new gewVec3();
         for(var t=0;t<  outTriangles.length;t++)
         {
           var triangle = outTriangles[t];
           var plane = new gewPlane(triangle.v0,triangle.v1,triangle.v2);
           normal.set(plane.a,plane.b,plane.c);
           
           var dis = plane.distanceToPoint(aabb.center);
           if(dis<0)
            normal.set(-plane.a,-plane.b,-plane.c);
           
           shapeModelMat.mulVec3NoTranslate(normal,normal);
           var angle = velocity.angleFrom(normal)*GEW_MATH_RADIAN_TO_DEGREE;
           
           if(angle>maxAngle)
           {
             maxAngle = angle;
             outNormal.set(normal.x,normal.y,normal.z);
           }
         }
        }
        if(test==GEW_OUT)
        {
          //console.log("Reject by aabb-shape test")
          return false;
        }  
      }
    }
    // Still not support collison bettween two shape ( too slow for js,i think)
    return true; 
  },
  updateCell:function()
  {
    this.cells = [];
    var body1 = this.body1;
    var body2 = this.body2;
    var cell1s = body1.sceneNode.quadTreeCells;
    var cell2s = body2.sceneNode.quadTreeCells;
    var cell1Len = cell1s.length;
    for(var i=0;i<cell1Len;i++ )
    {
      if( isInArray(cell1s[i],cell2s) )
        this.cells.push(cell1s[i]);  
    }
  },
  destroy:function()
  {
    var name = this.name;
    delete this.engine.collisionPairs[name];
    delete this.body1.collisionPairs[name];
    delete this.body2.collisionPairs[name];
  }
}


